package com.sx.service.user;

import com.sx.basic.exception.BasicException;
import com.sx.basic.service.BasicService;
import com.sx.basic.service.impl.BasicServiceImpl;
import com.sx.dao.user.UserRepository;
import com.sx.entity.finance.IncomeEntity;
import com.sx.entity.user.AmountEntity;
import com.sx.entity.user.UserEntity;
import com.sx.service.finance.IIncomeService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;

/**
 * @author AdinZ
 * @date 2020/11/18 14:26
 */
@Service
public class UserService extends BasicServiceImpl<UserRepository, UserEntity,Long>
        implements BasicService<UserEntity,Long> ,IUserService{

    @Resource private IIncomeService incomeService;
    @Resource private IAmountService amountService;
    @Resource private IInviteCodeService inviteCodeService;
    @Resource private IRelationService relationService;

    /**
     * 统一用户资金变动
     * @param uid 用户id
     * @param type 金额类型
     * @param amount 金额
     * @param sourceType 来源类型
     * @param sourceId 来源id
     * @param attribute 自定义属性
     * @return
     */
    @Override @Transactional
    public boolean amountChange(long uid, AmountEntity.AmountType type, BigDecimal amount, IncomeEntity.SourceType sourceType, Long sourceId, String attribute) {

        AmountEntity amountEntity = this.amountService.amountChange(type, uid, amount);
        IncomeEntity entity=new IncomeEntity();
        entity.setUid(uid);
        entity.setAfterAmount(amountEntity.getAmount());
        entity.setAttribute(attribute);
        entity.setAmount(amount);
        entity.setBeforeAmount(amountEntity.getBeforeAmount());
        entity.setSourceId(sourceId);
        entity.setSourceType(sourceType);
        entity.setType(type);
        this.incomeService.save(entity);
        return true;
    }

    /**
     * 统一用户资金变动
     * @param uid 用户id
     * @param type 金额类型
     * @param amount 金额
     * @param sourceType 来源类型
     * @param sourceId 来源id
     * @return
     */
    @Override @Transactional
    public boolean amountChange(long uid, AmountEntity.AmountType type, BigDecimal amount, IncomeEntity.SourceType sourceType, Long sourceId) {
        return this.amountChange(uid, type, amount, sourceType, sourceId,null);
    }

    /**
     * 统一创建用户/新用户必须走此接口
     * @param userEntity 用户资料实体
     * @return
     */
    @Override @Transactional
    public UserEntity createUser(UserEntity userEntity) {
        if (StringUtils.isEmpty(userEntity.getPhone())) throw new BasicException("手机号不能空");
        final String lockKey = "CREATE__" + userEntity.getPhone();
        try {
            if (!this.redisService.lock(lockKey)) throw new BasicException("请勿重复提交");
            if (this.existsPhone(userEntity.getPhone())) throw new BasicException("手机号已经存在");
            this.repository.save(userEntity);
            //创建用户账户,如果多个账户类型,可创建多个
            this.amountService.createAmount(AmountEntity.AmountType.MONEY, userEntity.getId(), BigDecimal.ZERO);
            //生成用户邀请码,
            this.inviteCodeService.inviteGen(userEntity.getId());
            //邀请人
            if(userEntity.getInviteUid()!=null){
                //注册关系链, 关系链最长20位
                this.relationService.registered(userEntity.getInviteUid(), userEntity.getId(),20);
            }
        } finally {
            this.redisService.unlock(lockKey);
        }
        return userEntity;
    }


    @Override @Transactional
    public boolean userState(Long[] ids, int state) {
        Integer i=  this.repository.updateState(ids,state);
        if(i==null)i=0;
        return i>0;
    }

    /**
     * 验证手机号是否存在
      * @param phone
     * @return
     */
    private boolean existsPhone(final String phone){
        long count=this.repository.count((Specification<UserEntity>) (root, cq, cb) -> cb.equal(root.get("phone"),phone));
        return count>0;
    }



}
